#pragma once
#include <iostream>
#include <memory>
#include <poll.h>
#include "Log.hpp"
#include "Socket.hpp"

using namespace Net_Work;
const static int g_defaultport = 8888;
const static int g_backlog = 16;
const static int num = 1024;

class PollServer
{
private:
    void HandlerEvent()
    {
        for (int i = 0; i < _num; i++)
        {
            if (_fds[i].fd == -1) // 1.判断是否合法
                continue;
            int fd = _fds[i].fd;
            short revents = _fds[i].revents;

            if (revents & POLLIN) // 2.数据是否就绪
            {
                // 新连接的到来
                // 有两种情况，一种是新连接到来了，还有一种是新数据到来了
                if (fd == _listensock->GetSockfd())
                {
                    lg.LogMessage(Info, "get a new link\n");
                    std::string clientip;
                    uint16_t clientport;
                    // accept不会阻塞！
                    int sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (sock == -1)
                    {
                        lg.LogMessage(Error, "accept error\n");
                        return;
                    }
                    lg.LogMessage(Info, "get a client, client info# %s, %d, fd: %d\n", clientip.c_str(), clientport, sock);

                    // 获取到一个链接了，可以直接进行read，write了吗？肯定不能
                    // 我们还不知道数据有没有就绪，只有select清楚数据有没有就绪
                    // 新链接fd来的时候，需要交给select托管起来，使用一个数组管理起来！

                    int pos = 0;
                    for (; pos < _num; pos++)
                    {
                        if (_fds[pos].fd == -1)
                        {
                            _fds[pos].fd = sock;
                            _fds[pos].events = POLLIN;
                            lg.LogMessage(Info, "get a new link, fd is : %d\n", sock);
                            break;
                        }
                    }
                    if (pos == _num)
                    {
                        close(sock);
                        lg.LogMessage(Error, "fds_array is full...\n");
                    }
                }
                else // 普通的读事件
                {
                    char buffer[1024];
                    ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        lg.LogMessage(Info, "client say# %s\n", buffer);
                        std::string message = "你好我是服务器, ";
                        message += buffer;
                        send(fd, message.c_str(), message.size(), 0);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit, maybe close or error, close fd : %d\n", fd);
                        close(fd);
                        _fds[i].fd = -1;
                        _fds[i].events = 0;
                        _fds[i].revents = 0;
                    }
                }
            }
        }
    }

public:
    PollServer(int port = g_defaultport)
        : _listensock(new TcpSocket()), _port(port), _isrunning(false), _num(num)
    {
    }
    ~PollServer()
    {
        delete[] _fds;
    }

    void Init()
    {
        _listensock->BuildListensocketMethod(_port, backlog);
        _fds = new struct pollfd[_num];
        for (int i = 0; i < _num; i++) // 将poll数组初始化一下
        {
            _fds[i].fd = -1;
            _fds[i].events = 0;
            _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock->GetSockfd();
        _fds[0].events |= POLLIN; // 写事件
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            PrintDebug();
            int timeout = -1; // 阻塞模式
            int s = poll(_fds, _num, timeout);
            switch (s)
            {
            case 0:
                lg.LogMessage(Info, "select timeout...\n");
                break;
            case -1:
                lg.LogMessage(Error, "select error\n");
                break;
            default:
            {
                lg.LogMessage(Info, "select success, begin event handler\n");
                HandlerEvent();
                break;
            }
            }
        }
        _isrunning = false;
    }

    void PrintDebug()
    {
        std::cout << "current select list is ";
        for (int i = 0; i < num; i++)
        {
            if (_fds[i].fd == -1)
            {
                continue;
            }
            else
            {
                std::cout << _fds[i].fd << " ";
            }
        }
        std::cout << std::endl;
    }

private:
    std::unique_ptr<Socket> _listensock;
    int _port;
    bool _isrunning;

    struct pollfd *_fds;
    int _num;
};
